/*  This file is part of IDalgo.

    CASpp is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CASpp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CASpp.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2014 Jérome LAURENS

    See https://code.google.com/p/idalgo/

*/

#ifndef IDALGO_SHARED_MACROS_H
#define IDALGO_SHARED_MACROS_H

#ifdef IDALGO_NS_BEGIN
#   error Find another macro name
#endif

#ifdef NO_NAMESPACE_IDALGO
#   define IDALGO_NS
#   define IDALGO_NS_BEGIN
#   define IDALGO_NS_END
#   define IDALGO_NS_USING
#else
#   define IDALGO_NS IDalgo
#   define IDALGO_NS_BEGIN namespace IDALGO_NS {
#   define IDALGO_NS_END }
#   define IDALGO_NS_USING using namespace IDALGO_NS;
#endif

// declare namespaces early:
IDALGO_NS_BEGIN
IDALGO_NS_END

#ifdef SHARED_NS_BEGIN
#   error Find another macro name
#endif

#ifdef NO_NAMESPACE_SHARED
#   define SHARED_NS
#   define SHARED_NS_BEGIN
#   define SHARED_NS_END
#   define SHARED_NS_USING
#else
#   define SHARED_NS Shared
#   define SHARED_NS_BEGIN namespace SHARED_NS {
#   define SHARED_NS_END }
#   define SHARED_NS_USING using namespace SHARED_NS;
#endif

// declare namespaces early:
SHARED_NS_BEGIN
SHARED_NS_END

#ifdef CASPP_NS_BEGIN
#   error Find another macro name
#endif

#ifdef NO_NAMESPACE_CASPP
#   define CASPP_NS
#   define CASPP_NS_BEGIN
#   define CASPP_NS_END
#   define CASPP_NS_USING
#else
#   define CASPP_NS CASpp
#   define CASPP_NS_BEGIN namespace CASPP_NS {
#   define CASPP_NS_END }
#   define CASPP_NS_USING using namespace CASPP_NS;
#endif

// declare namespaces early:
CASPP_NS_BEGIN
CASPP_NS_END

#ifdef PAXER_NS_BEGIN
#   error Find another macro name
#endif

#ifdef NO_NAMESPACE_PAXER
#   define PAXER_NS
#   define PAXER_NS_BEGIN
#   define PAXER_NS_END
#   define PAXER_NS_USING
#else
#   define PAXER_NS Paxer
#   define PAXER_NS_BEGIN namespace PAXER_NS {
#   define PAXER_NS_END }
#   define PAXER_NS_USING using namespace PAXER_NS;
#endif

// declare namespaces early:
PAXER_NS_BEGIN
PAXER_NS_END

// Following macros are used in the scope of the caspp namespace

#define IDALGO_STRINGIFY(_X) IDALGO_STRINGIFY_(_X)
#define IDALGO_STRINGIFY_(_X) #_X

#define CASPP_STRINGIFY IDALGO_STRINGIFY
#define PAXER_STRINGIFY IDALGO_STRINGIFY

#ifndef IDALGO_INLINE
#   define     IDALGO_INLINE static inline
#endif

#ifndef CASPP_INLINE
#   define      CASPP_INLINE IDALGO_INLINE
#endif
#ifndef PAXER_INLINE
#   define      PAXER_INLINE IDALGO_INLINE
#endif

#ifndef IDALGO_NO_THROW
#   define     IDALGO_NO_THROW throw()
#endif

#ifndef CASPP_NO_THROW
#   define      CASPP_NO_THROW IDALGO_NO_THROW
#endif
#ifndef PAXER_NO_THROW
#   define      PAXER_NO_THROW IDALGO_NO_THROW
#endif

#include <boost/current_function.hpp>
#include <boost/format.hpp>

#define IDalgo_ARGUMENT_NOT_NULL(WHAT) do {if(NOT THING(WHAT))throw(std::argument_error,"Unexpected NULL argument");} while(false)
#define CASpp_ARGUMENT_NOT_NULL IDalgo_ARGUMENT_NOT_NULL
#define Paxer_ARGUMENT_NOT_NULL IDalgo_ARGUMENT_NOT_NULL(WHAT)

#if __clang__
#   define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wformat-extra-args\"")
#   define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic pop")
#else
#   define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS
#   define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS
#endif

#define IDalgoAssertMsg(CONDITION, EXCEPTION, DESCRIPTION) \
    do {				\
    __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
        if (!(CONDITION)) {		\
            throw EXCEPTION(boost::str(boost::format("Unsatisfied %1%:%2%:%3%:%4%:%5%") % #CONDITION % __FILE__ % __LINE__ % __PRETTY_FUNCTION__% (DESCRIPTION))); \
        }				\
    __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
    } while(0)

#define IDalgoAssert(CONDITION,EXCEPTION) IDalgoAssertMsg(CONDITION, EXCEPTION, "")
#define IDalgoParameterAssert(CONDITION) IDalgoAssert((CONDITION), std::invalid_argument)
#define IDalgoRangeAssert(INDEX,MAX_BOUND) IDalgoAssertMsg((INDEX<MAX_BOUND), std::out_of_range, boost::str(boost::format("Invalid %1% value: %2%")% #INDEX % (INDEX)))
#define IDalgoRuntimeAssert(CONDITION) IDalgoAssert((CONDITION), std::runtime_error)

#define CASppAssertMsg IDalgoAssertMsg
#define CASppAssert IDalgoAssert
#define CASppParameterAssert IDalgoParameterAssert
#define CASppRangeAssert IDalgoRangeAssert
#define CASppRuntimeAssert IDalgoRuntimeAssert

#define PaxerAssertMsg IDalgoAssertMsg
#define PaxerAssert IDalgoAssert
#define PaxerParameterAssert IDalgoParameterAssert
#define PaxerRangeAssert IDalgoRangeAssert
#define PaxerRuntimeAssert IDalgoRuntimeAssert

#include <boost/shared_ptr.hpp>

#define IDALGO_DECLARE_TYPE_REF(__TYPE) \
    typedef boost::shared_ptr<__TYPE> __TYPE##Ref; \
    typedef boost::shared_ptr<__TYPE> const __TYPE##RefConst ; \
    typedef boost::shared_ptr<__TYPE const> __TYPE##ConstRef; \
    typedef boost::shared_ptr<__TYPE const> const __TYPE##ConstRefConst

#define IDALGO_DECLARE_CLASS_REF(__CLASS) \
    class __CLASS; \
    IDALGO_DECLARE_TYPE_REF(__CLASS)

#define CASPP_DECLARE_TYPE_REF IDALGO_DECLARE_TYPE_REF
#define CASPP_DECLARE_CLASS_REF IDALGO_DECLARE_CLASS_REF

#define PAXER_DECLARE_TYPE_REF IDALGO_DECLARE_TYPE_REF
#define PAXER_DECLARE_CLASS_REF IDALGO_DECLARE_CLASS_REF

#include "wrap.h"

#define IDALGO_DECLARE_TYPE_WRAP(__TYPE) \
    typedef Shared::Wrap<__TYPE> __TYPE##Wrap; \
    typedef Shared::Wrap<__TYPE> const __TYPE##WrapConst; \
    typedef Shared::Wrap<__TYPE const> __TYPE##ConstWrap; \
    typedef Shared::Wrap<__TYPE const> const __TYPE##ConstWrapConst

#define IDALGO_DECLARE_CLASS_WRAP(__CLASS) \
    class __CLASS; \
    IDALGO_DECLARE_TYPE_REF(__CLASS)

#define CASPP_DECLARE_TYPE_WRAP IDALGO_DECLARE_TYPE_WRAP
#define CASPP_DECLARE_CLASS_WRAP IDALGO_DECLARE_CLASS_WRAP

#define PAXER_DECLARE_TYPE_WRAP IDALGO_DECLARE_TYPE_WRAP
#define PAXER_DECLARE_CLASS_WRAP IDALGO_DECLARE_CLASS_WRAP

// DO NOT PUT DEFINITIONS HERE

#endif // IDALGO_SHARED_MACROS_H
